/**
 * Copyright (c) 2016-2021, Bosco.Liao (bosco_liao@126.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.iherus.shiro.redis.spring.boot.autoconfigure;

import org.iherus.shiro.cache.redis.config.RedisClusterConfiguration;
import org.iherus.shiro.cache.redis.config.RedisSentinelConfiguration;
import org.iherus.shiro.cache.redis.config.RedisStandaloneConfiguration;
import org.iherus.shiro.cache.redis.connection.RedisConnectionFactory;
import org.iherus.shiro.cache.redis.connection.redisson.RedissonConnectionFactory;
import org.iherus.shiro.redis.spring.boot.autoconfigure.ShiroRedisProperties.RedissonConfig;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 
 * @author Bosco.Liao
 * @since 2.0.0
 */
@Configuration
@ConditionalOnClass(RedissonClient.class)
@ConditionalOnMissingClass("org.springframework.data.redis.connection.RedisConnectionFactory")
public class RedissonConnectionFactoryConfiguration extends RedisConfigurationWrapper {

	private final ShiroRedisProperties properties;

	private final ObjectProvider<RedissonSslClientConfigurationCustomizer> customizerProvider;

	protected RedissonConnectionFactoryConfiguration(ShiroRedisProperties properties,
                                                     ObjectProvider<RedisStandaloneConfiguration> standaloneConfigProvider,
                                                     ObjectProvider<RedisSentinelConfiguration> sentinelConfigProvider,
                                                     ObjectProvider<RedisClusterConfiguration> clusterConfigProvider,
                                                     ObjectProvider<RedissonSslClientConfigurationCustomizer> customizerProvider) {
		
		super(properties, standaloneConfigProvider, sentinelConfigProvider, clusterConfigProvider);
		this.properties = properties;
		this.customizerProvider = customizerProvider;
	}

	@Bean(name = "x_redissonConnectionFactory", initMethod = "init", destroyMethod = "destroy")
	@ConditionalOnMissingBean(RedisConnectionFactory.class)
	public RedissonConnectionFactory connectionFactory() {
		return createRedissonConnectionFactory();
	}

	private RedissonConnectionFactory createRedissonConnectionFactory() {
		RedisSentinelConfiguration sentinelConfig = null;
		RedisClusterConfiguration clusterConfig = null;
		RedissonConnectionFactory factory = null;

		if ((sentinelConfig = getSentinelConfiguration()) != null) {
			factory = new RedissonConnectionFactory(sentinelConfig);
		} else if ((clusterConfig = getClusterConfiguration()) != null) {
			factory = new RedissonConnectionFactory(clusterConfig);
		} else {
			factory = new RedissonConnectionFactory(getStandaloneConfiguration());
		}
		
		applyProperties(factory);
		return factory;
	}

	private void applyProperties(RedissonConnectionFactory factory) {
		RedissonConfig redissonConfig = this.properties.getRedisson();
		RedissonSslClientConfiguration sslConfig = getRedissonSslClientConfiguration();

		factory.setClientName(redissonConfig.getClientName());
		factory.setConnectTimeout(redissonConfig.getConnectTimeout());
		factory.setSoTimeout(redissonConfig.getSoTimeout());

		factory.setConnectionMinIdleSize(redissonConfig.getConnectionMinIdleSize());
		factory.setConnectionPoolSize(redissonConfig.getConnectionPoolSize());

		// SSL
		factory.setUseSsl(redissonConfig.isSsl());
		factory.setSslTruststore(sslConfig.getSslTruststore());
		factory.setSslTruststorePassword(sslConfig.getSslTruststorePassword());
		factory.setSslKeystore(sslConfig.getSslKeystore());
		factory.setSslKeystorePassword(sslConfig.getSslKeystorePassword());
	}

	private RedissonSslClientConfiguration getRedissonSslClientConfiguration() {
		RedissonSslClientConfiguration.Builder builder = RedissonSslClientConfiguration.builder();
		customize(builder);
		return builder.build();
	}

	private void customize(RedissonSslClientConfiguration.Builder builder) {
		this.customizerProvider.orderedStream().forEach((customizer) -> customizer.customize(builder));
	}

}
